#pragma once 
#include <highgui.h>
#include "stdlib.h"
#include "FrameKey.h"

using namespace std;

template <class T>
class LivingPatch
{
public:
	static const int MaxTTL = 5;

protected:

	vector<CvPoint> _history;
	vector<FrameKey*> _frames;
	int _ttl;
	int _age;

	LivingPatch(FrameKey* key, int x, int y)
	{
		_history.push_back(cvPoint(x,y));
		_frames.push_back(key);

		_ttl = MaxTTL;
		_age = 1;

	}

	virtual void OnUpdate(FrameKey* key, T* patch){};
	
	void UpdateLifecycle(FrameKey* key, int x, int y)
	{
		_history.push_back(cvPoint(x,y));
		_frames.push_back(key);
		
		_ttl = MaxTTL;
		_age++;
	}
	virtual void OnSaveToFile() {};

public: 
	void Save(FILE* file)
	{
		fprintf(file, "Age:%i\n",_age);
		fprintf(file,"History:");
		for (int i = 0; i < _history.size(); i++)
		{
			CvPoint* p = &(_history[i]);
			fprintf(file,"{ %s, (%i,%i)}", _frames[i]->ToString(), p->x, p->y);
		}
		OnSaveToFile();
		fprintf(file,"\n\n");
	}

	void Update(FrameKey* key, T* patch)
	{
		OnUpdate(key, patch);

		CvPoint p = ((BasePatch*)patch)->GetPoint();
		UpdateLifecycle(key, p.x, p.y);
	}

	bool ReduceTTL()
	{
		_ttl--;
		return _ttl == 0;
	}

	int GetAge() { return _age; }

	vector<CvPoint>* GetHistory()
	{
		return &_history;
	}

	void DrawPath(IplImage* img, CvScalar pathColor, CvScalar currentPositionColor)
	{
		if (_history.size() > 1)
			{
				vector<CvPoint>::const_iterator leftIt = _history.begin();
				vector<CvPoint>::const_iterator rightIt = leftIt + 1;
				while (rightIt != _history.end())
				{
					cvLine(img, *leftIt, *rightIt, pathColor);
					leftIt++;
					rightIt++;
				}
			}
				
		cvCircle(img, _history[_history.size() - 1], 5, currentPositionColor);
	}

	virtual ~LivingPatch(){}

	int static Lifecycle(vector<T*>* v, FILE* file = NULL)
	{
		int deleted = 0;
		int i = 0; 
		while (i < v->size())
		{
			T* p = (*v)[i];
			if (((LivingPatch<T>*)p)->ReduceTTL())
			{
				if (file != NULL)
					p->Save(file);

				delete p;
				deleted++;

				v->erase(v->begin() + i);
			}
			else
				i++;
		}

		return deleted;
	}
};